using System;
using Fadd.Globalization;

namespace Fadd.Validation
{
    /// <summary>
    /// Base class for all Fadd validation attributes.
    /// </summary>
    /// <remarks>
    /// <para>
    /// Each validation class should document what their language entries should say, and their names.
    /// This should be done in the remarks section using a table list, example:
    /// <list type="table">
    ///     <listheader>
    ///         <term>ItemName</term>
    ///         <description>Language text</description>
    ///     </listheader>
    ///     <item>
    ///         <term>ValidateLetters</term>
    ///         <description>'{0}' may only contain letters.</description>
    ///     </item>
    ///     <item>
    ///         <term>ValidateLettersExtra</term>
    ///         <description>'{0}' may only contain letters and one of the following characters: {1}</description>
    ///     </item>
    /// </list>
    /// It's recommended that the item names (or terms in the table above) equals the validation class name.
    /// i.e. ValidateEmailAttributes adds a language item called "Email".
    /// </para>
    /// </remarks>
    public abstract class ValidateAttribute : Attribute
    {
        /// <summary>
        /// Validate value
        /// </summary>
        /// <param name="context">Can be used to send a context object to the validation class. Useful if you provide your own validation classes which need to get information from your application. <seealso cref="BeforeValidationEventArgs"/></param>
        /// <param name="value">value to validate</param>
        /// <returns>
        /// true if value passed the validation; otherwise false.
        /// </returns>
        public abstract bool Validate(object context, object value);

        /// <summary>
        /// Localize error if validation failed.
        /// </summary>
        /// <param name="fieldName">Localized field name.</param>
        /// <param name="validationLanguage">Language node with all validation translations.</param>
        /// <returns>A localized error message if the validation failed; otherwise null.</returns>
        /// <example>
        /// <code>
        /// attribute.Localize("FirstName", "'{0}' is required"); 
        /// // will return "'{0}' is required" if the validation failed, else null.
        /// </code>
        /// </example>
        public abstract string Format(string fieldName, ILanguageNode validationLanguage);


        /// <summary>
        /// Determines if the validation class support the specified type.
        /// </summary>
        /// <param name="type">Property/Value type.</param>
        /// <returns>true if the type is supported.</returns>
        public abstract bool SupportsType(Type type);

        /// <summary>
        /// Check's whether a value is empty or not.
        /// </summary>
        /// <param name="value">value to check.</param>
        /// <returns>true if the value is empty.</returns>
        public static bool IsEmpty(object value)
        {
            return IsEmpty(value, null);
        }

        /// <summary>
        /// Check's whether a value is empty or not.
        /// </summary>
        /// <param name="value">value to check.</param>
        /// <param name="emptyValue">value is considered to be not specified if the value matches this parameter</param>
        /// <returns>true if the value is empty.</returns>
        public static bool IsEmpty(object value, object emptyValue)
        {
        	return value == emptyValue || ValueChecker.IsEmpty(value);
        }
    }
}